/* -*- c++ -*- */
/*
 * This file is part of the SD Project.
 *
 * Authors: Cleiber Marques da Silva <cleiber@lisha.ufsc.br>
 * 			Odilson Tadeu Valle <odilson@sj.ifsc.edu.br>
 * 
 * SD Project is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; version 2 of the License.
 */

#include <iostream>
#include <ctime>

#include "send.h"
#include "listener.hh"

namespace sd {

	send::send(int _argc, char **_argv, sd::clock *_clock, sd::delivery *_delivery, sd::window *_window, std::string _id, std::vector<std::string> ids) : omni_thread()
	{
		argc = _argc;
		argv = _argv;
		clock = _clock;
		delivery = _delivery;
		window = _window;
		id = _id;
		recv_ids = ids;

		// Istance objects recv
		for (unsigned int i = 0; i < recv_ids.size(); i++) {
			std::cout << "Instance object to receiver id = " << recv_ids[i] << std::endl;
			receiver.push_back(new recv(recv_ids[i]));
		}

		// Instance object to messages
		sd::config config(id);
		messages = config.get_groups();
	}	

	void send::sendto(listener_ptr tobj, std::string first, sd::config *second, sd::clock *clock)
	{
		CORBA::Any a;
		struct_message tp;
		const std::string message_prefix = "message";

		// test group name for prefix
		if (first.substr(0, message_prefix.length()) == message_prefix) {
			tp.type = second->type_int("type");
			tp.id = second->type_int("id");
			tp.mesg = second->type_string("mesg").c_str();
			tp.seq = atoi(first.substr(message_prefix.length()).c_str());
		}
	
		for (unsigned int i = 0; i < clock->timestamp.size(); i++)
			tp.timestamp[i] = clock->get_timestamp(i);

		a <<= tp;
		invokeOp(tobj, a);
	}

	void send::invokeOp(listener_ptr& tobj, const CORBA::Any& a)
	{	
	  tobj->listen(a);
	}

	void send::run(void *arg)
	{
		unsigned int i, recv_resolved = 0;
		std::cout << "Thread send" << std::endl;

	//std::string teste; std::cin >> teste;

		// Find all CORBA::Ojects in Name Service
		//for (unsigned int i = 0; i < recv_ids.size(); i++) {
		for (i = 0; recv_resolved < 3; i = (i + 1) % recv_ids.size()) {
			omni_thread::sleep(1);
			if (CORBA::is_nil(receiver[i]->listener_ref)) {
				receiver[i]->find_recv(argc, argv);
				if (CORBA::is_nil(receiver[i]->listener_ref)) {
					std::cout << "Try find others objects" << std::endl;
					continue;
				}
				std::cout << "Find receiver id = " << recv_ids[i] << std::endl;
				recv_resolved++;
			}
		}
	
		std::map<std::string, sd::config*>::iterator cfg = messages.begin();
		while (cfg != messages.end()) {
			if (id == "1") {
				int ok = delivery->should_send();
				if (!((ok & 0x1) || ((ok & 0x2) && (ok & 0x4)))) {
					omni_thread::sleep(1);
					//std::cout << "Debug" << std::endl;
					continue;
				}
			}

			// Update clock
			clock->mutex.lock();
			clock->inc_timestamp(atoi(id.c_str()) - 1);
			clock->mutex.unlock();

			// Send mesg to receivers
			for (i = 0; i < recv_ids.size(); i++) {
				srand(time(0));
				//omni_thread::sleep((rand() % 3) + 1);
				sendto(receiver[i]->listener_ref, cfg->first, cfg->second, clock);
			}

			cfg++;
		}
	}
}
